package com.xinhe.web.service;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.QueryResults;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.xinhe.web.common.Result;
import com.xinhe.web.entity.*;
import com.xinhe.web.reposity.*;
import com.xinhe.web.request.OrderByShopCartModel;
import com.xinhe.web.request.TeamBuyOrderModel;
import com.xinhe.web.response.*;
import com.xinhe.web.session.UserSessionManager;
import com.xinhe.web.util.DateUtil;
import com.xinhe.web.util.Snowflake;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import java.util.*;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

@Service
public class TeamBuyOrderService {
    @Autowired
    TeamBuyRepository teamBuyRepository;
    @Autowired
    TeamBuyOrderRepository teamBuyOrderRepository;
    @Autowired
    ValueConfigRepository valueConfigRepository;
    @Autowired
    OrderRepository orderRepository;
    private ReadWriteLock leaderLock = new ReentrantReadWriteLock();
    private ReadWriteLock memberLock = new ReentrantReadWriteLock();
    private ReadWriteLock payStatusLock = new ReentrantReadWriteLock();
    @Autowired
    private UserSessionManager userSessionManager;
    @Autowired
    private TeamGoodsRepository teamGoodsRepositoryo;
    @Autowired
    private OrderAddressService orderAddressService;
    @Autowired
    private OrderAddressRepository orderAddressRepository;
    @Autowired
    private GoodsRepository goodsRepository;
    @Autowired
    private OrderService orderService;
    @Autowired
    private OrderItemRepository orderItemRepository;
    //查询工厂
    private JPAQueryFactory queryFactory;
    @Autowired
    private Provider<EntityManager> entityManager;
    @PostConstruct
    public void init() {
        queryFactory = new JPAQueryFactory(entityManager);
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveTeamPayTimeoutInterval() {
        Integer teamTimeoutMinuteStr = 0;
        //获取配置的认拼团支付超时分钟,5
        Optional<ValueConfig> valueConfig = valueConfigRepository.findById("team-pay-timeout-minute");
        if (valueConfig.isPresent() && StringUtils.isNotBlank(valueConfig.get().getValue())){
            teamTimeoutMinuteStr = Integer.valueOf(valueConfig.get().getValue());
        }
        List<TeamBuyOrder> timeoutTeamOrders = teamBuyOrderRepository.findByTimeout(teamTimeoutMinuteStr);
        if (CollectionUtils.isNotEmpty(timeoutTeamOrders)) {
            for (TeamBuyOrder teamOrder : timeoutTeamOrders) {
                teamOrder.setStatus("TIMEOUT");
                teamBuyOrderRepository.saveAndFlush(teamOrder);
                orderRepository.updateStatusById(teamOrder.getOrderId(),"TIMEOUT");
                TeamBuy teamBuy = this.teamBuyRepository.findById(teamOrder.getTeamBuyId()).get();
                //加入人数-1
                teamBuy.setJoinAmount(Integer.valueOf(teamBuy.getJoinAmount().intValue() - 1));
                if (teamBuy.getJoinAmount().intValue() <= 0) {
                    teamBuy.setStatus("FAILURE");
                    teamBuy.setEndTime(new Date());
                }
                teamBuyRepository.saveAndFlush(teamBuy);
            }
        }
    }
    @Transactional(rollbackFor = Exception.class)
    public void savePay(Long orderId) {
        TeamBuyOrder teamOrder = this.teamBuyOrderRepository.findByOrderId(orderId);
        //待支付
        if (teamOrder != null && "UN_PAY".equals(teamOrder.getStatus())) {
            //PAYED("拼团中")
            teamOrder.setStatus("PAYED");
            TeamBuy teamBuy = this.teamBuyRepository.findById(teamOrder.getTeamBuyId()).get();
            teamBuy.setPayAmount(Integer.valueOf(teamBuy.getPayAmount().intValue() + 1));
            if (teamBuy.getPayAmount().equals(teamBuy.getMemberAmount())) {
                teamBuy.setStatus("SUCCESS");
                this.teamBuyOrderRepository.updateStatusByTeamBuyIdAndStatus(teamBuy.getId(),"PAYED", "SUCCESS");
                if (teamBuy.getStatus().equals("SUCCESS")) {
                    List<TeamBuyOrder> teamBuyOrders = this.teamBuyOrderRepository.findByTeamBuyId(teamBuy.getId());
                    if (CollectionUtils.isNotEmpty(teamBuyOrders)) {
                        for (TeamBuyOrder teamBuyOrder : teamBuyOrders) {
                            Order order = this.orderRepository.findById(teamBuyOrder.getOrderId()).get();
                            order.setStatus("SUCCESS");
                            this.orderRepository.save(order);
                        }
                    }
                }
            } else {
                teamBuy.setStatus("TEAMING");
            }
            if (teamBuy.getLeaderUserId().equals(teamOrder.getBuyerUserId())) {
                teamBuy.setStartTime(new Date());
            }
            this.teamBuyRepository.saveAndFlush(teamBuy);
        }
    }

    public QueryResults<TeamBuyOrderView> pageTeamBuyOrder(Long buyerUserId, Long teamGoodsId, Long goodsId, Long teamBuyId,
                                                           Long orderId, String status, int pageNum, int pageSize) {
        QTeamBuyOrder qTeamBuyOrder = QTeamBuyOrder.teamBuyOrder;
        QTeamBuy qTeamBuy = QTeamBuy.teamBuy;
        QOrder qOrder = QOrder.order;
        BooleanBuilder builder = new BooleanBuilder();
        //builder.and(qTeamBuy.removed.eq(0));
        if (!Objects.isNull(buyerUserId)) {
            builder.and(qTeamBuyOrder.buyerUserId.eq(buyerUserId));
        }
        if (!Objects.isNull(teamGoodsId)) {
            builder.and(qTeamBuyOrder.teamGoodsId.eq(teamGoodsId));
        }
        if (!Objects.isNull(goodsId)) {
            builder.and(qTeamBuyOrder.goodsId.eq(goodsId));
        }
        if (!Objects.isNull(teamBuyId)) {
            builder.and(qTeamBuyOrder.teamBuyId.eq(teamBuyId));
        }
        if (!Objects.isNull(orderId)) {
            builder.and(qTeamBuyOrder.orderId.eq(orderId));
        }
        if (!Objects.isNull(status)) {
            builder.and(qTeamBuyOrder.status.eq(status));
        }
        return queryFactory.select(
                        Projections.bean(
                                TeamBuyOrderView.class,
                                qTeamBuyOrder.id,
                                qTeamBuyOrder.buyerUserId,
                                qTeamBuyOrder.teamBuyId,
                                qTeamBuyOrder.teamGoodsId,
                                qTeamBuyOrder.orderId,
                                qTeamBuyOrder.status
                        )
                ).from(qTeamBuyOrder)
                .leftJoin(qTeamBuy).on(qTeamBuyOrder.teamBuyId.eq(qTeamBuy.id))
                .leftJoin(qOrder).on(qTeamBuyOrder.orderId.eq(qTeamBuy.id))
                .where(builder).offset(pageNum * pageSize).limit(pageSize).fetchResults();
    }


    public QueryResults<TeamOrderByUserView> pageTeamOrderByUser(Long buyerUserId, String status, int pageNum, int pageSize) {
        QTeamBuyOrder qTeamBuyOrder = QTeamBuyOrder.teamBuyOrder;
        QTeamBuy qTeamBuy = QTeamBuy.teamBuy;
        QOrder qOrder = QOrder.order;
        BooleanBuilder builder = new BooleanBuilder();
        //builder.and(qTeamBuy.removed.eq(0));
        if (!Objects.isNull(buyerUserId)) {
            builder.and(qTeamBuyOrder.buyerUserId.eq(buyerUserId));
        }
        if (!Objects.isNull(status)) {
            builder.and(qTeamBuyOrder.status.eq(status));
        }
        return queryFactory.select(
                        Projections.bean(
                                TeamOrderByUserView.class,
                                qTeamBuyOrder.id,
                                qTeamBuyOrder.buyerUserId,
                                qTeamBuyOrder.teamBuyId,
                                qTeamBuyOrder.teamGoodsId,
                                qTeamBuyOrder.orderId,
                                qTeamBuyOrder.status.as("teamOrderStatus"),
                                qTeamBuy.status.as("teamBuyStatus"),
                                qOrder.code,
                                qOrder.orderFee,
                                qOrder.orderAmount,
                                qOrder.payTime
                        )
                ).from(qTeamBuyOrder)
                .leftJoin(qTeamBuy).on(qTeamBuyOrder.teamBuyId.eq(qTeamBuy.id))
                .leftJoin(qOrder).on(qTeamBuyOrder.orderId.eq(qTeamBuy.id))
                .where(builder).offset(pageNum * pageSize).limit(pageSize).fetchResults();
    }

    @Transactional
    public Result saveTeamOrderByLeader(OrderByShopCartModel model) {
        System.out.println("参数为:" + model);
        this.leaderLock.readLock().lock();
        try {
            Long userId = this.userSessionManager.getUserId();
            TeamBuy savedTeamBuy = this.teamBuyRepository.findOneByLeaderUserIdAndStatus(userId, "TEAMING", model.getTeamGoodsId());
            if (null != savedTeamBuy) {
                return Result.failed(101,"已经发起过拼团，请完成后再发起");
            }
            savedTeamBuy = this.teamBuyRepository.findOneByLeaderUserIdAndStatus(userId,"UN_PAY", model.getTeamGoodsId());
            System.out.println("有值啊:" + savedTeamBuy);
            if (null != savedTeamBuy) {
                return Result.failed(102,"已经发起过拼团，请完成后再发起");
            }
            TeamGoods teamGoods = this.teamGoodsRepositoryo.findByGoodsId(model.getTeamGoodsId());
            if (teamGoods == null) {
                return Result.failed(102,"当前商品未开启拼团活动");
            }
            Map<String,Object> orderByShopCartView = (Map<String, Object>) this.orderService.saveOrderByShopCart(model).getData();
            Calendar instance = Calendar.getInstance();
            TeamBuy teamBuy = new TeamBuy();
            teamBuy.setGoodsId(teamGoods.getGoodsId());
            teamBuy.setLeaderUserId(userId);
            teamBuy.setMemberAmount(teamGoods.getMemberAmount());
            teamBuy.setStartTime(instance.getTime());
            teamBuy.setTeamGoodsId(teamGoods.getId());
            teamBuy.setStatus("UN_PAY");
            teamBuy.setJoinAmount(Integer.valueOf(teamBuy.getJoinAmount().intValue() + 1));
            this.teamBuyRepository.save(teamBuy);
            TeamBuyOrder teamOrder = new TeamBuyOrder();
            teamOrder.setBuyerUserId(userId);
            teamOrder.setOrderId(Long.valueOf(((String)orderByShopCartView.get("orderIdsStr")).split(",")[0]));
            teamOrder.setStatus("UN_PAY");
            teamOrder.setTeamGoodsId(teamBuy.getTeamGoodsId());
            teamOrder.setTeamBuyId(teamBuy.getId());
            this.teamBuyOrderRepository.save(teamOrder);
            return Result.ok(teamOrder);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.failed(103,"系统失败");
        } finally {
            this.leaderLock.readLock().unlock();
        }
        //return Result.ok();
    }

    @Transactional
    public Result saveTeamOrderByMember(OrderByShopCartModel model) {
        this.memberLock.readLock().lock();
        try {
            Long userId = this.userSessionManager.getUserId();
            TeamBuy teamBuy = (TeamBuy)this.teamBuyRepository.findById(model.getTeamBuyId()).get();
            if (teamBuy.getMemberAmount().intValue() <= teamBuy.getJoinAmount().intValue()) {
                return Result.failed(101,"拼团已满，不能再加入");
            }
            if (teamBuy.getLeaderUserId().equals(userId)) {
                return Result.failed(102,"你不能加入自己的拼团");
            }
            TeamBuyOrder savedTeamOrder = this.teamBuyOrderRepository.findOneByTeamBuyIdAndBuyerUserId(teamBuy.getId(), userId);
            if (null != savedTeamOrder) {
                return Result.failed(101,"你已加入该拼团，不能重复加入");
            }
            Map<String,Object> map = (Map<String,Object>)this.orderService.saveOrderByShopCart(model).getData();
            TeamGoods teamGoods = this.teamGoodsRepositoryo.findById(teamBuy.getTeamGoodsId()).get();
            TeamBuyOrder teamOrder = new TeamBuyOrder();
            teamOrder.setBuyerUserId(userId);
            teamOrder.setOrderId(Long.valueOf(((String)map.get("orderIdsStr")).split(",")[0]));
            teamOrder.setStatus("UN_PAY");
            teamOrder.setTeamGoodsId(teamBuy.getTeamGoodsId());
            teamOrder.setTeamBuyId(teamBuy.getId());
            this.teamBuyOrderRepository.save(teamOrder);
            teamBuy.setJoinAmount(Integer.valueOf(teamBuy.getJoinAmount().intValue() + 1));
            this.teamBuyRepository.saveAndFlush(teamBuy);
            return Result.ok(teamOrder);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.failed(103,"系统开小差了");
        } finally {
            this.memberLock.readLock().unlock();
        }
    }

    public Result detailTeamBuyOrder(Long teamBuyOrderId) {
        QTeamBuyOrder qTeamBuyOrder = QTeamBuyOrder.teamBuyOrder;
        QTeamBuy qTeamBuy = QTeamBuy.teamBuy;
        QOrder qOrder = QOrder.order;
        BooleanBuilder builder = new BooleanBuilder();
        //builder.and(qTeamBuy.removed.eq(0));
        builder.and(qTeamBuyOrder.id.eq(teamBuyOrderId));
        TeamOrderByUserView teamOrderByUserView = queryFactory.select(
                        Projections.bean(
                                TeamOrderByUserView.class,
                                qTeamBuyOrder.id,
                                qTeamBuyOrder.buyerUserId,
                                qTeamBuyOrder.teamBuyId,
                                qTeamBuyOrder.teamGoodsId,
                                qTeamBuyOrder.orderId,
                                qTeamBuyOrder.status.as("teamOrderStatus"),
                                qTeamBuy.status.as("teamBuyStatus"),
                                qOrder.orderAmount,
                                qOrder.orderFee,
                                qOrder.payTime,
                                qOrder.code
                        )
                ).from(qTeamBuyOrder)
                .innerJoin(qTeamBuy).on(qTeamBuyOrder.teamBuyId.eq(qTeamBuy.id))
                .innerJoin(qOrder).on(qTeamBuyOrder.orderId.eq(qTeamBuy.id))
                .where(builder).fetchOne();

        OrderAddressView orderAddressView = this.orderAddressRepository.findByGoodsOrderId(teamOrderByUserView.getOrderId());
        if (null != orderAddressView) {
            teamOrderByUserView.setOrderAddressView(orderAddressView);
        }
        List<OrderItem> orderItems = this.orderItemRepository.findByOrderId(teamOrderByUserView.getOrderId());
        teamOrderByUserView.setOrderItems(orderItems);
        TeamBuyDetailView view = new TeamBuyDetailView();
        TeamBuy teamBuy = this.teamBuyRepository.findById(teamOrderByUserView.getTeamBuyId()).get();
        if (teamBuy != null) {
            BeanUtils.copyProperties(teamBuy, view);
            view.setStatus((teamBuy.getStatus() != null) ? teamBuy.getStatus() : null);
            Calendar instance = Calendar.getInstance();
            instance.setTime(view.getStartTime());
            if (teamBuy.getStatus().equals("UN_PAY")) {
                //拼团支付超时分钟 5
                Integer teamTimeoutMinuteStr = 5;
                instance.add(12, teamTimeoutMinuteStr.intValue());
            } else if (teamBuy.getStatus().equals("TEAMING")) {
                //拼团超时小时 24
                Integer teamTimeoutHour = 24;
                instance.add(11, teamTimeoutHour.intValue());
            }
            view.setEndTime(instance.getTime());
            //List<TeamBuyOrderMemberView> viewList = this.teamBuyRepository.findMemberList(teamBuy.getId());
            List<Map<String, Object>> mapList = this.teamBuyRepository.findMemberList(teamBuy.getId());
            List<TeamBuyOrderMemberView> viewList = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(mapList)){
                for (Map<String, Object> map : mapList){
                    TeamBuyOrderMemberView teamBuyOrderMemberView = new TeamBuyOrderMemberView();
                    Long userId = (Long) map.get("userId");
                    String nickname = (String) map.get("nickname");
                    String iconPath = (String) map.get("iconPath");
                    teamBuyOrderMemberView.setUserId(userId);
                    teamBuyOrderMemberView.setNickname(nickname);
                    teamBuyOrderMemberView.setIconPath(iconPath);
                    viewList.add(teamBuyOrderMemberView);
                }
            }
           view.setMemberViews(viewList);
        }
        teamOrderByUserView.setTeamBuyDetailView(view);
        return Result.ok(teamOrderByUserView);
    }

    public Result detailTeamOrderByOrderId(Long orderId) {
        TeamBuyOrder teamBuyOrder = this.teamBuyOrderRepository.findByOrderId(orderId);
        return Result.ok(teamBuyOrder);
    }

    @Transactional
    public Result cancelTeamOrder(Long teamBuyOrderId) {
        TeamBuyOrder teamOrder = (TeamBuyOrder)this.teamBuyOrderRepository.findById(teamBuyOrderId).get();
        teamOrder.setStatus("CANCEL");
        this.teamBuyOrderRepository.saveAndFlush(teamOrder);
        TeamBuy teamBuy = (TeamBuy)this.teamBuyRepository.findById(teamOrder.getTeamBuyId()).get();
        teamBuy.setJoinAmount(Integer.valueOf(teamBuy.getJoinAmount().intValue() - 1));
        teamBuy.setStatus("CANCEL");
        this.teamBuyRepository.saveAndFlush(teamBuy);
        this.orderService.cancelOrder(teamOrder.getOrderId());
        return Result.ok();
    }

    private String generateGoodsOrderCode() {
        StringBuilder code = new StringBuilder("T");
        code.append(DateUtil.formatDate(new Date(), "yyyyMMdd"));
        double codeRandom = Math.random() * 100000.0D;
        code.append((int)codeRandom);
        return code.toString();
    }

    public Result delete(Long teamBuyOrderId) {
        teamBuyOrderRepository.deleteById(teamBuyOrderId);
        return Result.ok();
    }

    public Result saveModel(TeamBuyOrderModel model) {
        TeamBuyOrder teamBuyOrder = new TeamBuyOrder();
        BeanUtils.copyProperties(model, teamBuyOrder);
        teamBuyOrder.setId(Snowflake.generateId());
        teamBuyOrderRepository.save(teamBuyOrder);
        return Result.ok();
    }
}
